package models;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class BetsManager
{
    public Map<String, Integer> bets;
    public Map<String, Integer> money;
    public List<String>         folders;

    public boolean              firstBetMade;
    public boolean              allIn;
    public int                  maxBet;
    public String               maxBetUuidl;
    public int                  pool;

    public BetsManager()
    {
        this.bets = new HashMap<String, Integer>();
        this.money = new HashMap<String, Integer>();
        this.folders = new ArrayList<String>();
        this.firstBetMade = false;
        this.allIn = false;
        this.maxBet = 0;
        this.maxBetUuidl = "";
        this.pool = 0;
    }

    public void addPlayer(String uuid, int money)
    {
        this.money.put(uuid, money);
        this.bets.put(uuid, 0);
    }

    public void rmPlayer(String uuid)
    {
        this.money.remove(uuid);
    }

    public int getMoney(String uuid)
    {
        return this.money.get(uuid);
    }

    public void putFee(String uuid, int fee)
    {
        int currentMoney = this.money.get(uuid) - fee;
        this.money.remove(uuid);
        this.money.put(uuid, currentMoney);
        this.pool += fee;
    }

    public int getBet(String uuid)
    {
        return this.bets.get(uuid);
    }

    public int getPool()
    {
        int pool = this.pool;
        for (Map.Entry<String, Integer> entry : this.bets.entrySet())
        {
            pool += entry.getValue();
        }
        return pool;
    }

    public boolean auctionCanEnd()
    {
        if (((this.money.size() - this.folders.size()) < 2)
                && (this.money.size() > 2))
        {
            return true;
        }
        int prev = -1;
        int bet;
        for (Map.Entry<String, Integer> entry : this.bets.entrySet())
        {
            bet = entry.getValue();
            boolean isFolder = this.folders.contains(entry.getKey());
            if ((prev > -1) && (prev != bet) && !isFolder)
            {
                return false;
            }
            if (!isFolder)
            {
                prev = bet;
            }
        }
        return true;
    }

    public void resetAuction()
    {
        String uuid;
        Iterator<Map.Entry<String, Integer>> it = this.bets.entrySet()
                .iterator();
        while (it.hasNext())
        {
            Map.Entry<String, Integer> entry = it.next();
            it.remove();
        }
        for (Map.Entry<String, Integer> entry : this.money.entrySet())
        {
            uuid = entry.getKey();
            this.bets.put(uuid, 0);
        }
        this.folders.clear();
        this.firstBetMade = false;
        this.allIn = false;
        this.maxBet = 0;
        this.maxBetUuidl = "";
        this.pool = 0;
    }

    public int countWin(String uuid)
    {
        int win = this.pool;
        int winnerBet = this.bets.get(uuid);
        String currentUuid;
        for (Map.Entry<String, Integer> entry : this.bets.entrySet())
        {
            currentUuid = entry.getKey();
            if (this.allIn)
            {
                int looserBet = entry.getValue();
                int delta = 0;
                if (winnerBet > looserBet)
                {
                    win += winnerBet;
                    delta = winnerBet - looserBet;
                    this.addCash(currentUuid, delta);
                }
                else
                {
                    win += entry.getValue();
                }
            }
            else
            {
                win += entry.getValue();
            }
        }
        return win;
    }

    public void addCash(String uuid, int cash)
    {
        int currentCash = this.money.get(uuid);
        this.money.remove(uuid);
        this.money.put(uuid, currentCash + cash);
    }

    public boolean canCheck()
    {
        return !this.firstBetMade;
    }

    public boolean canBet()
    {
        return !this.firstBetMade;
    }

    public boolean canBet(String uuid, int bet)
    {
        if (!this.canBet() || this.folders.contains(uuid))
        {
            return false;
        }
        if (bet <= 0)
        {
            return false;
        }
        if (!(this.money.get(uuid) > bet))
        {
            return false;
        }
        return true;
    }

    public boolean canRaise(String uuid)
    {
        if (!this.firstBetMade || this.allIn || this.folders.contains(uuid))
        {
            return false;
        }
        if (!(this.money.get(uuid) > this.maxBet))
        {
            return false;
        }
        return true;
    }

    public boolean canRaise(String uuid, int bet)
    {
        if (!this.canRaise(uuid))
        {
            return false;
        }
        if (bet <= 0)
        {
            return false;
        }
        return true;
    }

    public boolean canCall(String uuid)
    {
        if (!this.firstBetMade || this.allIn || this.folders.contains(uuid))
        {
            return false;
        }
        if (!(this.money.get(uuid) >= this.maxBet))
        {
            return false;
        }
        return true;
    }

    public boolean canAllIn(String uuid)
    {
        if (!this.firstBetMade || this.folders.contains(uuid))
        {
            return false;
        }
        if (this.canCall(uuid) || (this.money.get(uuid) <= 0))
        {
            return false;
        }
        return true;
    }

    public void check(String uuid)
    {
        if (!this.canCheck())
        {
            // throw
        }
    }

    public void bet(String uuid, int bet)
    {
        if (!this.canBet(uuid, bet))
        {
            // throw
        }
        int currentMoney = this.money.get(uuid) - bet;
        int currentBet = this.bets.get(uuid) + bet;
        this.money.remove(uuid);
        this.money.put(uuid, currentMoney);
        this.bets.remove(uuid);
        this.bets.put(uuid, currentBet);
        this.firstBetMade = true;
        this.maxBet = currentBet;
        this.maxBetUuidl = uuid;
    }

    public void raise(String uuid, int bet)
    {
        if (!this.canRaise(uuid, bet))
        {
            // throw
        }
        int currentMoney = this.money.get(uuid);
        int currentBet = this.bets.get(uuid);
        int delta = (this.maxBet - currentBet) + bet;
        this.money.remove(uuid);
        this.money.put(uuid, currentMoney - delta);
        this.bets.remove(uuid);
        this.bets.put(uuid, currentBet + delta);
        this.maxBet = currentBet + delta;
        this.maxBetUuidl = uuid;
    }

    public void call(String uuid)
    {
        if (!this.canCall(uuid))
        {
            // throw
        }
        int currentMoney = this.money.get(uuid);
        int currentBet = this.bets.get(uuid);
        int moneyDelta = this.maxBet - currentBet;
        this.money.remove(uuid);
        this.money.put(uuid, currentMoney - moneyDelta);
        this.bets.remove(uuid);
        this.bets.put(uuid, currentBet + moneyDelta);
    }

    public void fold(String uuid)
    {
        this.folders.add(uuid);
    }

    public void allIn(String uuid)
    {
        if (!this.canAllIn(uuid))
        {
            // throw
        }
        int currentMoney = this.money.get(uuid);
        int currentBet = this.bets.get(uuid);
        int allIn = currentMoney + currentBet;
        this.money.remove(uuid);
        this.money.put(uuid, 0);
        this.bets.remove(uuid);
        this.bets.put(uuid, allIn);
        if (allIn > this.maxBet)
        {
            this.maxBet = allIn;
            this.maxBetUuidl = uuid;
        }
    }

    public static void main(String[] args)
    {
        BetsManager bm = new BetsManager();
        bm.addPlayer("one", 500);
        bm.addPlayer("two", 500);
        bm.addPlayer("three", 500);
        System.out.printf("%5b\n", bm.canCheck());
        System.out.printf("%5b\n", bm.canBet());
        System.out.printf("%5b\n", bm.canRaise("one"));
        System.out.printf("%5b\n", bm.canCall("one"));
        System.out.printf("%5b\n", bm.canAllIn("one"));
        bm.bet("one", 100);
        System.out.println();
        System.out.printf("%5b\n", bm.canCheck());
        System.out.printf("%5b\n", bm.canBet());
        System.out.printf("%5b\n", bm.canRaise("one"));
        System.out.printf("%5b\n", bm.canCall("one"));
        System.out.printf("%5b\n", bm.canAllIn("one"));
        bm.bet("two", 450);
        System.out.println();
        System.out.printf("%5b\n", bm.canCheck());
        System.out.printf("%5b\n", bm.canBet());
        System.out.printf("%5b\n", bm.canRaise("one"));
        System.out.printf("%5b\n", bm.canCall("one"));
        System.out.printf("%5b\n", bm.canAllIn("one"));
        bm.fold("one");
        System.out.println();
        System.out.printf("%5b\n", bm.canCheck());
        System.out.printf("%5b\n", bm.canBet());
        System.out.printf("%5b\n", bm.canRaise("one"));
        System.out.printf("%5b\n", bm.canCall("one"));
        System.out.printf("%5b\n", bm.canAllIn("one"));
    }
}
